# -*- coding:utf-8 -*-
import time

time1 = time.time()
# DFA算法 Deterministic Finite Automaton 确定有穷自动机

class DFAFilter(object):
    def __init__(self):
        self.keyword_chains = {}  # 关键词链,是一个字典,这是一个字典树,前缀树
        self.delimit = '\x00'

    # 构造一个字典树,是违禁词经过构造形成的树
    def add(self, keyword):  # 传入一个单词
        keyword = keyword.lower()
        chars = keyword.strip()  # 将传入的字符串前后的空字符去除掉
        if not chars:  # 如果说传入的字符串去掉两边的空格之后,为空,则直接返回
            return
        level = self.keyword_chains  # level是关键词链的引用
        for i in range(len(chars)):  # 遍历传入词语的每一个字
            if chars[i] in level:  # 如果有一个字在level中,就遍历它的数组
                level = level[chars[i]]  # 以该字作为key,level作为其新的引用
            else:
                if not isinstance(level, dict):
                    break
                for j in range(i, len(chars)):
                    level[chars[j]] = {}
                    last_level, last_char = level, chars[j]
                    level = level[chars[j]]
                last_level[last_char] = {self.delimit: 0}
                break
        if i == len(chars) - 1:
            level[self.delimit] = 0
        # print(i)

    def parse(self, path):
        with open(path, encoding='utf-8') as f:  # 以utf-8的编码打开文本文档
            for keyword in f:  # keyword是里面的一行一行的内容
                self.add(str(keyword).strip())  # 调用add方法,将里面的违禁词做成树
                # print(self.keyword_chains)

    def filter(self, message, repl="*"):
        message = message.lower()
        ret = []  # 返回过滤后的文本
        start = 0  # 指向要进行匹配的字的下标
        while start < len(message):
            level = self.keyword_chains
            step_ins = 0  # 记录违禁字的数量,然后往准备好的输出来的句子里面添加*替换它
            for char in message[start:]:
                if char in level:
                    step_ins += 1
                    if self.delimit not in level[char]:
                        level = level[char]
                    else:
                        ret.append(repl * step_ins)
                        start += step_ins - 1  # 调整当前检测的下标的位置
                        break
                else:
                    ret.append(message[start])
                    break
            else:
                ret.append(message[start])
            start += 1
        return ''.join(ret)


if __name__ == "__main__":
    gfw = DFAFilter()  # 声明一个DFA对象
    path = ""  # 词库的路径
    gfw.parse(path)  # 根据词库进行构造树  放在初始化中以提高效率
    print(gfw.keyword_chains)
    text = "待检测文本"
    result = gfw.filter(text)  # 过滤并返回过滤之后的文本
    print(text)
    print(result)
    time2 = time.time()
    print('总共耗时：' + str(time2 - time1) + 's')
